\chapter{错误处理}

\section{错误种类}

Tenon中的错误分为系统内置错误和用户定义错误二类。

\subsection{系统错误}
在程序运行过程中会遇到一些错误情况，如除数为零，系统遇到这种情况会自动抛出一个错误。

\subsection{用户错误}
用户在函数的常规块内可以通过raise语句抛出错误。这里的raise后面必须跟一个错误编号，
用户可以使用的错误编号在1到90之内。

在中断处理函数里也可以raise错误。

\section{错误处理}

当在函数的常规语句中发生了错误（包括系统自动抛出的错误和用户raise的错误），系统会寻找当前函数的
错误处理器。如果当前函数有错误处理器，会跳转到错误处理器继续执行。如果当前函数没有错误处理器，
则会交给系统错误处理器处理。

当在函数的错误处理器里发生了错误，则会交给系统错误处理器处理。

\section{错误处理器}

\subsection{系统错误处理器}
系统内置一个系统错误处理器。系统错误处理器的处理是停止程序的执行。

\subsection{函数错误处理器}
函数错误处理器由函数的error部分定义。函数错误处理器有2种声明方式。

一种是error后面不跟错误编号列表，这种错误处理器捕获所有的错误。在这种错误处理器中应该用下面列
出的5种处理语句对错误进行处理。如果不处理，错误会被直接交给系统错误处理器。

另一种是error后面跟一个错误编号的列表，这种错误处理器只捕获列表中出现的错误，对于没有出现在列表中的错
误，会自动继续向上抛出。对于列表中的错误，如果没有用下面列出的5种处理语句进行处理，会直接交给系统错误处理器。

在函数错误处理器中可以通过不带参数的raise语句继续抛出错误（包括自动继续抛出的错误）。
在错误处理器中继续抛出的错误，系统会在函数调用栈上向上寻找含有错误处理器的被调函数。直到找到
第一个含有错误处理器的被调函数，将抛出的错误交给它的错误处理器处理。如果调用栈上没有找到包含错误处理
器的被调函数，则交给系统错误处理器处理。

注意，这里所说的继续抛出的错误是指错误处理器抛出当前捕获的错误，而不是错误处理器自身产生的新的错误。
如果是错误处理器自身产生的新的错误，如发生了除零，则会直接交给系统错误处理器处理，因为错误处理器是不
带错误处理器的。错误处理器不能用带参数的raise语句主动抛出新错误。

中断处理函数的错误处理器继续抛出的错误会直接交给系统错误处理器处理，因为中断处理函数不算作当前调用栈的一部分，
它是由系统直接调用的。

下面列出在错误处理器中可以执行的几种处理语句。

\begin{itemize}
    \item raise: 继续向调用栈上方抛出错误，系统自动寻找第一个包含错误处理器的被调函数。
    \item retry: 重复执行本函数中发生错误的语句。
    \item trynext: 执行本函数中发生错误的语句后面的语句。
    \item return: 从本函数调用中返回。
    \item exit: 停止程序的执行。
\end{itemize}

如果当执行到错误处理器末尾没有遇到以上几种处理，则会交给系统错误处理器处理。

注意retry和trynext在处理从调用栈下方抛出来的错误的时候，执行的是它们所在的函数发生错误的语句（应该是
一个函数调用语句），而不是调用栈下方错误最初发生所在的函数的语句。

\section{总结}

当在函数中发生错误时，系统寻找当前函数的错误处理器。如果没有，则交给系统错误处理器处理。

当在函数错误处理器中发生错误时，交给系统错误处理器处理。

函数错误处理器可以继续抛出错误，系统会在调用栈上向上找错误处理器。如果没有，则交给系统错误处理器处
理。中断处理函数的错误处理器继续抛出的错误直接由系统错误处理器处理。
